package top.juc.plugin.idea.openfeignx.util;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.file.PsiDirectoryImpl;
import org.apache.commons.lang3.ObjectUtils;
import top.juc.plugin.idea.openfeignx.annotation.Annotation;
import top.juc.plugin.idea.openfeignx.dto.FindClassDTO;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import static top.juc.plugin.idea.openfeignx.util.FileTypes.PROPERTIES_SUFFIX;
import static top.juc.plugin.idea.openfeignx.util.FileTypes.YAML_SUFFIX;

public class ModuleUtils {
    private static final Logger LOG = Logger.getInstance(ModuleUtils.class);

    public static FindClassDTO findClassByAnnotation(Project project, List<Annotation> annotations) {
        Module[] modules = ModuleManager.getInstance(project).getModules();
        if(ObjectUtils.isEmpty(modules)){
            return new FindClassDTO();
        }
        ConcurrentHashMap<Annotation,List<PsiClass>> resultMap = new ConcurrentHashMap<>();
        ConcurrentHashMap<Module,List<VirtualFile>> moduleConfigMap = new ConcurrentHashMap<>();
        for (Module module : modules) {
            List<PsiFile> files = getModulePsiFileList(module, project);
            for (PsiFile psiFile : files) {
                try {
                    PsiElement[] children = psiFile.getChildren();
                    for (PsiElement element : children) {
                        if (element instanceof PsiClass) {
                            PsiClass psiClass = (PsiClass) element;
                            for (Annotation annotation : annotations) {
                                if (JavaUtils.isAnnotationPresent(psiClass, annotation)) {
                                    resultMap.computeIfAbsent(annotation, k -> new ArrayList<>()).add(psiClass);
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                VirtualFile virtualFile = psiFile.getVirtualFile();
                if (virtualFile != null) {
                    if(YAML_SUFFIX.contains(virtualFile.getFileType().getDefaultExtension()) || PROPERTIES_SUFFIX.equals(virtualFile.getFileType().getDefaultExtension())) {
                        moduleConfigMap.computeIfAbsent(module, k -> new ArrayList<>()).add(virtualFile);
                    }
                }
            }
        }
        FindClassDTO result = new FindClassDTO();
        result.setAnnotationClassMap(resultMap);
        result.setModuleConfigMap(moduleConfigMap);
        return result;
    }


    private static List<PsiFile> getModulePsiFileList(Module module, Project project) {
        VirtualFile[] sourceRoots = ModuleRootManager.getInstance(module).getSourceRoots(false);
        List<PsiFile> fileList = new LinkedList();
        int size = sourceRoots.length;

        try {
            for(int i = 0; i < size; ++i) {
                VirtualFile sourceRoot = sourceRoots[i];
//                if (sourceRoot.getName().contains("java")) {
                    VirtualFile canonicalFile = sourceRoot.getCanonicalFile();
                    PsiManagerImpl psiManager = new PsiManagerImpl(project);
                    PsiDirectory psiDirectory = new PsiDirectoryImpl(psiManager, canonicalFile);
                    fileList.addAll(getPsiFileListFromPsiDirectory(psiDirectory));
//                }
            }

            return fileList;
        } catch (Exception var11) {
            var11.printStackTrace();
            throw var11;
        }
    }

    private static List<PsiFile> getPsiFileListFromPsiDirectory(PsiDirectory psiDirectory) {
        List<PsiFile> fileList = new LinkedList();
        PsiFile[] files = psiDirectory.getFiles();
        int var6;
        if (files != null && files.length > 0) {
            PsiFile[] var4 = files;
            int var5 = files.length;

            for(var6 = 0; var6 < var5; ++var6) {
                PsiFile psiFile = var4[var6];
                fileList.add(psiFile);
            }
        }

        PsiDirectory[] subdirectories = psiDirectory.getSubdirectories();
        if (subdirectories != null && subdirectories.length > 0) {
            PsiDirectory[] var10 = subdirectories;
            var6 = subdirectories.length;

            for(int var11 = 0; var11 < var6; ++var11) {
                PsiDirectory psiDirectory1 = var10[var11];
                fileList.addAll(getPsiFileListFromPsiDirectory(psiDirectory1));
            }
        }

        return fileList;
    }

}
